
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;

namespace MxitAPI
{
	
	/**
	 * This class uses an HTTP connection to send messages and recieve a response.
	 * The response is stored in the message object  
	 */
	public class HttpMessageTransceiver : MessageTransceiver
	{
		
		static log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod().DeclaringType );
		
		public HttpMessageTransceiver() {
		}
		
		/**
		 * Sends a message to the server and waits for a response
		 * @param message the input message to be sent, is modified in this method by the addition of the response from the Mxit server
		 */
		public override void SendMessage( ProtocolMessage message ) {
			
			MessageResponseHandler messageResponseHandler = message.MessageResponseHandler;
			
			StringBuilder packedString = new StringBuilder();
			
			// Get the server information
			HttpServerInfo serverInfo = ModelFacade.Instance.GetServerInfo() as HttpServerInfo;
			if ( serverInfo == null ) throw new MxitException( "An instance of an HttpServerInfo was not found." );
			
			// Create the message header
			string[] requestData = message.GetRequestData();
			log.Debug( requestData );
			
			packedString.Append( "id=" + ModelFacade.Instance.GetLoginName() + "&" );
			packedString.Append( "s=" );
			if ( serverInfo.SessionID != 0 ) {
				packedString.Append( serverInfo.SessionID + "\u0001");
			}
			packedString.Append( serverInfo.SequenceNumber + "&" );
			packedString.Append( "cm=" + ( int ) message.ProtocolMessageType + "&" );
			serverInfo.IncrementSequenceNumber();
			
			// Create the message body
			packedString.Append( "ms=" );
			foreach (string request in requestData) {
				packedString.Append( request + "\u0001" );
			}
			
			// Remove the final field terminator
			packedString.Remove( packedString.Length - 1, 1 );
			
			// Send the request and store the response
			string url = serverInfo.Address + packedString.ToString();
			
			//log.Info( url );
			
			HttpWebRequest webRequest = ( HttpWebRequest ) WebRequest.Create( url );
			//webRequest.Timeout = serverInfo.Timeout;
			webRequest.Proxy = serverInfo.Proxy;
			HttpWebResponse webResponse = ( HttpWebResponse ) webRequest.GetResponse();
			Stream receiveStream = webResponse.GetResponseStream();
			
			// Read the response into an array of bytes
			long contentLength = webResponse.ContentLength;
			byte[] buffer = new byte[ contentLength ];
			receiveStream.Read( buffer, 0, ( int ) contentLength );
			
			// Convert the array of bytes into a string
			StringBuilder responseStringBuilder = new StringBuilder();
			for ( int i = 0; i < contentLength; ++i ) {
				// Todo remove this debugging code
				if ( buffer[i] == 2 )
					Console.WriteLine( "i ==2 [{0}]", i );
				
				responseStringBuilder.Append( Char.ConvertFromUtf32( buffer[i] ) );
			}
			string responseString = responseStringBuilder.ToString();
			
			log.Debug( responseString.Replace( "\u0000", "!!" ) );
			
			string[] packetArr = responseString.Split( ( char ) 2 );
			List<ProtocolMessage> returnProtocolMessages = new List<ProtocolMessage>();
			
			foreach ( string packet in packetArr ) {
				if ( packet != String.Empty )
					returnProtocolMessages.Add( PopulateMessage( packet, message ) );
			}
			
			webResponse.Close();
			receiveStream.Close();
			System.Threading.Thread.Sleep(1000);
			
			// Calls the method that handles the message that has been update by the response from the mxit servers response from the mxit servers
			for ( int i = 0; i < returnProtocolMessages.Count ; ++i ) {
				// If this is the first response it must match with the request and the hanler has been passed in
				if ( i == 0 && messageResponseHandler != null )
					messageResponseHandler( returnProtocolMessages[i] );
				else
					Handler.GetHandler( returnProtocolMessages[i] ).HandleResponseProtocolMessage( returnProtocolMessages[i] );
			}
			/*if ( messageResponseHandler != null ){
				foreach ( ProtocolMessage returnProtocolMessage in returnProtocolMessages ) {
					messageResponseHandler( returnProtocolMessage );
				}
			}*/
			
		}		
		/*
		private ProtocolMessage PopulateMessage( ProtocolMessage protocolMessage, string packet ) {
			
			string[] tempOuterStrArr = packet.Split( ( char ) 0 );
			
			ProtocolMessage returnProtocolMessage;
				
			// If the response message is the same command number as the request message, clone the message for the request variables and add the response
			if ( protocolMessage.ProtocolMessageType == ( ProtocolMessageType ) Int32.Parse( tempOuterStrArr[0] ) )
				returnProtocolMessage = ( ProtocolMessage ) Activator.CreateInstance( protocolMessage.GetType() );
			else
				returnProtocolMessage = ProtocolMessageCreator.CreateProtocolMessage( Int32.Parse( tempOuterStrArr[0] ) );
			
			// Populate a jagged string array with the response.
			// Rows are delimited by \0 and individulal fields ( columns ) by \1
			string[][] responseArr = new string[ tempOuterStrArr.Length ][];
			for ( int i = 0; i < tempOuterStrArr.Length; ++i ){
				string[] tempInnerStrArr = tempOuterStrArr[i].Split( ( char ) 1 );
				responseArr[i] = new string[ tempInnerStrArr.Length ];
				
				for ( int j = 0; j < tempInnerStrArr.Length; ++j ){
					responseArr[i][j] = tempInnerStrArr[j];
					//Console.WriteLine( tempInnerStrArr[j] );
				}
			}
			
			log.Debug( responseArr );
			
			// Set the response variables in the message
			returnProtocolMessage.SetResponse( responseArr );
			
			return returnProtocolMessage;
		}*/
		
	}
}
